package com.ltu.ai.sparkdesk.websocket;

import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.websocket.EncodeException;
import javax.websocket.Session;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ltu.ai.sparkdesk.websocket.iat.IatSocketClient;
import com.ltu.ai.sparkdesk.websocket.ultra.ResponSparkData.RoleContent;
import com.ltu.ai.sparkdesk.websocket.ultra.SparkSocketClient;
import com.ltu.domain.mp_entity.AccountEntity;
import com.ltu.domain.mp_entity.customize.DeviceEntity;
import com.ltu.domain.mp_entity.customize.SessionInfoEntity;
import com.ltu.domain.mp_entity.customize.SessionRecordEntity;
import com.ltu.enums.SysDict;
import com.ltu.model.response.base.CodeDataResp;
import com.ltu.model.response.statistic.PubStatisticVO;
import com.ltu.service.AccountService;
import com.ltu.service.customize.SessionInfoService;
import com.ltu.service.customize.SessionRecordService;

import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;

@Slf4j
@Component
public class AiContextManager { 
	public static ConcurrentMap<String, IatContext>  IatContextMap = new ConcurrentHashMap<String, IatContext>();  
    // appid
	public static final String APPID = "dc8a62dd";
    // appid对应的secret_key
	public static final String SECRET_KEY = "YmE1ZjlmYzhiNjlhOWJkMDM3NGQ2OGNj";
	public static final String API_KEY = "1ca514e4a594f8abdca752bb458e1c18";
 
	@Autowired
	private SessionRecordService sessionRecordService;
	@Autowired
	private SessionInfoService sessionInfoService;
	@Autowired
	private AccountService accountService;

	
	
	/**
	 * @Description: 建立语音识别IAT的URL签名字符串
	 * @author 李生
	 * @date 2024-10-17 06:04:58 
	 */
    public static String getAuthUrl(String hostUrl) throws Exception {
        URL url = new URL(hostUrl);
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = format.format(new Date());
        StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
                append("date: ").append(date).append("\n").//
                append("GET ").append(url.getPath()).append(" HTTP/1.1");
        //System.out.println(builder);
        Charset charset = Charset.forName("UTF-8");
        Mac mac = Mac.getInstance("hmacsha256");
        SecretKeySpec spec = new SecretKeySpec(SECRET_KEY.getBytes(charset), "hmacsha256");
        mac.init(spec);
        byte[] hexDigits = mac.doFinal(builder.toString().getBytes(charset));
        String sha = Base64.getEncoder().encodeToString(hexDigits);
        //System.out.println(sha);
        String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", API_KEY, "hmac-sha256", "host date request-line", sha);
        //System.out.println(authorization);
        HttpUrl httpUrl = HttpUrl.parse("https://" + url.getHost() + url.getPath()).newBuilder().//
                addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(charset))).//
                addQueryParameter("date", date).//
                addQueryParameter("host", url.getHost()).
                build();
        return httpUrl.toString();
    }
    
    /**
     * @Description: IAT的结果发给客户端
     * @author 李生
     * @date 2024-10-22 12:46:02 
     * @param deviceNo
     * @param msg
     * @param role
     * @param saveFlag
     */
    public  void  responClient(String deviceNo,String msg,SysDict.SessionRole role,Boolean saveFlag) {
    	SessionRecordEntity record = new SessionRecordEntity();
    	record.setDeviceMac(deviceNo)
    		  .setContent(msg)
    		  .setRole(role.getName())
    		  .setCreateTime(new Date())
    		  .setSessionId(Integer.parseInt(IatContextMap.get(deviceNo).getSessionEntity().getId()))
    	;
    	if(saveFlag) 
    		sessionRecordService.save(record);
  
    	responClient( deviceNo,record);
		
    }
    
    /**
     * @Description: 广告推送
     */
    @Async(value = "customServiceExecutor")
    public  void  pushAd(List<String> deviceNos) {
    		String role = SysDict.SessionRole.AD.getName();
    		for (String deviceNo : deviceNos) {
    			if(!IatContextMap.containsKey(deviceNo))
    				continue;
				JSONObject   msg = new JSONObject();
				msg.put("role", role);
				msg.put("pullFlag", 1);
				responClient(deviceNo,msg);
			}
	
    }
    
    /**
     * @Description: 星火大模型的结果发给客户端
     * @author 李生
     * @date 2024-10-22 12:46:25 
     * @param deviceNo
     * @param msg
     * @param role
     */
    public  void  responClient(String deviceMac,Object msg) {
    	try {
    		  Session session = AiContextManager.IatContextMap.get(deviceMac).getDeviceClient();
              if(!ObjectUtils.isEmpty(session)) {
                  if (session.isOpen()) {
                      session.getBasicRemote().sendObject( CodeDataResp.valueOfSuccess(msg));
                  }else{
                	  AiContextManager.IatContextMap.remove(deviceMac);
                	  log.error("deviceNo设备已断开，停止发送消息");
                  }
              }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (EncodeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    @Async(value = "customServiceExecutor")
    public void  saveSessionRecord(SessionRecordEntity entity,SessionInfoEntity session) {
    	if(entity !=null)
    		sessionRecordService.save(entity);
    	if(session !=null)
    		sessionInfoService.updateById(session);
    }
    

    public String  getCurSessionQRCode(SessionInfoEntity entity) {
    	return sessionInfoService.getCurSessionQRCode(entity);
    }
    
    public  void  cutSession(String deviceMac) {
    	if(!IatContextMap.containsKey(deviceMac))
    		return;
    	IatContext  context = IatContextMap.get(deviceMac);
//    	if(context.getLegalSocketClient()!=null && context.getLegalSocketClient().isOpen()) {
//    		context.getLegalSocketClient().close();
//    		context.setLegalSocketClient(null);
//    	}
    	
    	if(!CollectionUtils.isEmpty(context.getHistoryList())) 
    		context.getHistoryList().clear();
    	context.setSessionEntity(null);
    	log.info("\n  清除会话 ");
    }
    
    
    public  SessionInfoEntity createSessionEntity(DeviceEntity  device) {
		SessionInfoEntity entity = new SessionInfoEntity();
		 entity.setDeviceMac(device.getDeviceNo())
		 		.setDeviceName(device.getDeviceName())
		 		.setDeviceId(Integer.parseInt(device.getId()))
			   .setStatus("1")
			   .setDevicePosition(device.getDevicePosition())
			   ;
		 entity.setDeviceType(device.getDeviceType());
		 entity.setTotalToken(0);
		 entity.setTotalQuestion(0);
		 sessionInfoService.save(entity);
		 return entity;
    }
    
    
    /**
     * @Description: 绑定会话所属用户
     * @author 李生
     * @date 2024-11-04 06:30:13 
     */
//	@Async(value = "customServiceExecutor")
	public void  bindUser2Session(String userId, String nickName, String headPhoto, String userPhone, Integer sessionId) {
		SessionInfoEntity old = this.sessionInfoService.getById(sessionId);
		UpdateWrapper<SessionInfoEntity>  up1 = new UpdateWrapper<SessionInfoEntity>();
		up1.lambda().set(SessionInfoEntity :: getUserId	, userId)
					.set(SessionInfoEntity :: getUserName , nickName)
					.set(SessionInfoEntity :: getUserPhone, userPhone)
					.set(SessionInfoEntity :: getUserAvatar, headPhoto)
					.eq(SessionInfoEntity :: getId , sessionId);
		
		old.setUserId(Integer.parseInt(userId));
		old.setUserName(nickName);
		old.setUserPhone(userPhone);
		old.setUserAvatar(headPhoto);
		this.sessionInfoService.updateById(old);
		
		UpdateWrapper<SessionRecordEntity>  up2 = new UpdateWrapper<SessionRecordEntity>();
		up2.lambda().set(SessionRecordEntity :: getUserId	, userId)
					.eq(SessionRecordEntity :: getSessionId , sessionId);
		this.sessionRecordService.update(up2);
		
		if(!IatContextMap.containsKey(old.getDeviceMac()))
    		return;
    	IatContext  context = IatContextMap.get(old.getDeviceMac());
    	
    	if(context.getSessionEntity()!=null &&  StringUtils.equals( context.getSessionEntity().getId(), old.getId()))
    		context.getSessionEntity().setUserId(Integer.parseInt(userId));
	    	context.getSessionEntity().setUserName(nickName);
	    	context.getSessionEntity().setUserPhone(userPhone);
	    	context.getSessionEntity().setUserAvatar(headPhoto);
		//
	    // 查出所有客服经理的账号，
	    //统计每个客服经理的会话 升序
	    //将本次会话绑定数量最少的那个 客服经理
	    	List<AccountEntity> accounts =  accountService.getAccount3();
	    	if(CollectionUtils.isEmpty(accounts)) 
	    		return;
	    	//分组在线和不在线客服经理
	    	List<AccountEntity>  accounts1= accounts.stream().filter(a -> a.getOnlineState().equals(true)).collect(Collectors.toList());
	    	if(CollectionUtils.isEmpty(accounts1))
	    		accounts1= accounts.stream().filter(a -> a.getOnlineState().equals(false)).collect(Collectors.toList());

	    	List<PubStatisticVO>  counts = sessionInfoService.countField0ByAccount();
	    	AccountEntity  bindAccount3 = null;
	    	//没有记录则取第一个客服经理绑定会话，
	    	if(CollectionUtils.isEmpty(counts)) 
	    		 bindAccount3 = accounts1.get(0);
	    	else {
	    	//优先筛选没有记录的 客服经理  即待跟进记录数=0 的
	    		List<String> accountIds = counts.stream().map(a -> a.getId()).collect(Collectors.toList());
	    		List<AccountEntity>  accounts2 =	accounts1.stream().filter(a -> accountIds.contains( a.getId()) == false ).collect( Collectors.toList());
	    		if(!CollectionUtils.isEmpty(accounts2))
	    			bindAccount3 = accounts2.get(0);
	    		else {//如果客服经理都有记录 则按记录数最少的顺序取第一个
	    			Optional<AccountEntity> aa = null;
	    			for (PubStatisticVO item : counts) {
	    				aa = accounts1.stream().filter(a -> a.getId().equals(item.getId())).findFirst();
	    				if(aa.isPresent())
	    					break;
					}
	    			bindAccount3 = aa.get();
	    		}
	    	}
	    	old.setAccountId(Integer.parseInt(bindAccount3.getId()));
	    	old.setAccountName(bindAccount3.getRealName());
	    	this.sessionInfoService.updateById(old);
	    
	    	
	}
	
	
	
    
	
	public static class IatContext{
		//语音文件路径
		private String filePath;
		//对应的设备
		private String deviceMac;
		//对应设备的webSocektClient
		private Session  deviceClient;
//		private LegalSocketClient legalSocketClient;
		private SparkSocketClient sparkSocketClient;
		
		private  IatSocketClient  iatClient;
		private  DeviceEntity  deviceEntity;
		
		//存到数据库的
		private SessionInfoEntity  sessionEntity;
		//星火律法大模型的问题
		private String   legalQuestion = "";
		//讯飞星火认知大模型的历史对话存储
		private  List<RoleContent> historyList=new ArrayList<>(); // 对话历史存储集合
		
		public IatContext(String deviceMac, Session deviceClient) {
			super();
			this.deviceMac = deviceMac;
			this.deviceClient = deviceClient;
		}
		
		
		public String getFilePath() {
			return filePath;
		}
		public void setFilePath(String filePath) {
			this.filePath = filePath;
		}
		public String getDeviceMac() {
			return deviceMac;
		}
		public void setDeviceMac(String deviceMac) {
			this.deviceMac = deviceMac;
		}
		public Session getDeviceClient() {
			return deviceClient;
		}
		public void setDeviceClient(Session deviceClient) {
			this.deviceClient = deviceClient;
		}
		public SessionInfoEntity getSessionEntity() {
			return sessionEntity;
		}
		public void setSessionEntity(SessionInfoEntity sessionEntity) {
			this.sessionEntity = sessionEntity;
		}
		public  List<RoleContent> getHistoryList() {
			return historyList;
		}
		public  void setHistoryList(List<RoleContent> historyList) {
			this.historyList = historyList;
		}
		
//		public LegalSocketClient getLegalSocketClient() {
//			return legalSocketClient;
//		}
//
//		public void setLegalSocketClient(LegalSocketClient legalSocketClient) {
//			this.legalSocketClient = legalSocketClient;
//		}
		
		public String getLegalQuestion() {
			return legalQuestion;
		}

		public SparkSocketClient getSparkSocketClient() {
			return sparkSocketClient;
		}


		public void setSparkSocketClient(SparkSocketClient sparkSocketClient) {
			this.sparkSocketClient = sparkSocketClient;
		}


		public void setLegalQuestion(String legalQuestion) {
			this.legalQuestion = legalQuestion;
		}

		public IatSocketClient getIatClient() {
			return iatClient;
		}


		public void setIatClient(IatSocketClient iatClient) {
			this.iatClient = iatClient;
		}

		public DeviceEntity getDeviceEntity() {
			return deviceEntity;
		}


		public void setDeviceEntity(DeviceEntity deviceEntity) {
			this.deviceEntity = deviceEntity;
		}


		/**
		 * 检查内容是否超过9000的长度,是的话清理签名的内容
		 */
	    public  void checkContextMax(){  // 由于历史记录最大上线1.2W左右，需要判断能否加入历史
	        int history_length=0;
	        Integer index =-1;
	        for(int i =this.historyList.size()-1;i>0;i--){
	        	RoleContent temp =this.historyList.get(i);
	            history_length=history_length+temp.getContent().length();
	            if(history_length>10000) {
	            	index = i;
	            	break;
	            }
	        }
	        if(index > -1) {
	        	 for(int i = 0;i<=index;i++){
	        		 this.historyList.remove(i);
	     	    }
	        }
		
	}
	    }	
}
